package com.ywu.standard.gateway.handler.user;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.ywu.application.spi.dto.UserRoleAuthDto;
import com.ywu.application.spi.spi.YwuApplicationSpi;
import com.ywu.boot.config.BootConfigAppConfig;
import com.ywu.boot.context.YwuContext;
import com.ywu.boot.context.YwuContextHolder;
import com.ywu.boot.context.YwuContextRole;
import com.ywu.boot.context.YwuContextUser;
import com.ywu.common.constant.CommonConstant;
import com.ywu.common.gson.GsonUtils;
import com.ywu.common.result.CommonResult;
import com.ywu.common.utils.AesUtils;
import com.ywu.standard.gateway.handler.user.impl.UserHandlerInterface;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @ClassName UserRoleHandler
 * @Description TODO
 * @Author GroundDemo
 * @Date 2024/5/26 12:19
 * @Version 1.0
 **/
@Component
@Slf4j
@Order(3)
public class UserRoleHandler implements UserHandlerInterface {
    private static final String USER_ROLE_HEADER_KEY = "X-Pix-Ywu-User-Role";

    private static final String GUEST_ACCOUNT = "guest";

    @Autowired
    private YwuApplicationSpi ywuApplicationSpi;

    @Autowired
    private BootConfigAppConfig bootConfigAppConfig;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private static final String YWU_GATEWAY_USER_ROLE_REDIS_KEY = "YWU_GATEWAY_USER_ROLE:gateway:";

    @Override
    public Object handle(ServerWebExchange exchange) {
        log.debug("UserRoleHandler begin");
        if (YwuContextHolder.getCurrentContext().isFilterChain()) {
            log.info("UserRoleHandler isFilterChain is true");
            return exchange;
        }
        YwuContext currentContext = YwuContextHolder.getCurrentContext();
        YwuContextUser ywuContextUser = currentContext.getYwuContextUser();
        List<YwuContextRole> ywuContextRoles = new ArrayList<>();
        if (!GUEST_ACCOUNT.equals(ywuContextUser.getUserAccount())) {
            // 优先从缓存中获取
            String redisInfo = redisTemplate.opsForValue().get(YWU_GATEWAY_USER_ROLE_REDIS_KEY + ywuContextUser.getUserAccount());
            if (Objects.nonNull(redisInfo)) {
                log.debug("gateway query role info using redis cache");
                ywuContextRoles = GsonUtils.deserializeList(redisInfo, YwuContextRole.class);
            } else {
                UserRoleAuthDto userRoleAuthDto = new UserRoleAuthDto();
                userRoleAuthDto.setUserId(ywuContextUser.getId());
                // 支持异步调用
                CompletableFuture<CommonResult<Object>> commonResultCompletableFuture =
                        CompletableFuture.supplyAsync(() -> ywuApplicationSpi.queryUserRoleInfo(userRoleAuthDto));
                CommonResult<Object> objectCommonResult;
                try {
                    objectCommonResult = commonResultCompletableFuture.get();
                } catch (InterruptedException | ExecutionException e) {
                    log.error("handleUserRole error {}", e.getMessage());
                    return CommonResult.error().setCode(CommonConstant.USER_ROLE_QUERY_INFO_ERROR).setErrorCode(CommonConstant.USER_ROLE_QUERY_INFO_ERROR_MESSAGE)
                            .setMessage("用户角色查询异常!");
                }
                // 判断是否成功
                if (!StringUtils.equals("200", objectCommonResult.getCode())) {
                    log.error("handleUserRole res error {}", objectCommonResult.getMessage());
                    return CommonResult.error().setCode(CommonConstant.USER_ROLE_QUERY_INFO_ERROR).setErrorCode(CommonConstant.USER_ROLE_QUERY_INFO_ERROR_MESSAGE)
                            .setMessage("用户角色查询异常!");
                }
                String serialize = GsonUtils.serialize(objectCommonResult.getData());
                ywuContextRoles = GsonUtils.deserializeList(serialize, YwuContextRole.class);
                // 添加缓存
                redisTemplate.opsForValue().set(YWU_GATEWAY_USER_ROLE_REDIS_KEY + ywuContextUser.getUserAccount(), serialize);
                redisTemplate.expire(YWU_GATEWAY_USER_ROLE_REDIS_KEY + ywuContextUser.getUserAccount(), 1, TimeUnit.HOURS);
            }
        }
        // 如果用户当前不存在 游客 角色，自动给用户添加一个 游客角色
        setGuestRole(ywuContextRoles);
        currentContext.setYwuContestRole(ywuContextRoles);
        // 序列化数据
        String userRoleJson = GsonUtils.serialize(ywuContextRoles);
        String encrypt;
        try {
            encrypt = AesUtils.encrypt(userRoleJson, bootConfigAppConfig.getSecretKey());
        } catch (Exception e) {
            log.error("handleUserRole encrypt error {}", e.getMessage());
            return CommonResult.error().setCode(CommonConstant.USER_ROLE_QUERY_INFO_ERROR).setErrorCode(CommonConstant.USER_ROLE_QUERY_INFO_ERROR_MESSAGE)
                    .setMessage("用户角色信息加密异常!");
        }
        log.debug("UserRoleHandler userRoleInfo header is {}", encrypt);
        ServerHttpRequest mutatedUserRoleRequest = exchange.getRequest().mutate().header(USER_ROLE_HEADER_KEY, encrypt).build();
        return exchange.mutate().request(mutatedUserRoleRequest).build();
    }

    /**
    * @Author GroundDemo
    * @Description 设置游客角色
    * @Date 20:04 2024/8/17
    * @Param [ywuContextRoles]
    * @return void
    **/
    private void setGuestRole(List<YwuContextRole> ywuContextRoles) {
        List<YwuContextRole> filter = ywuContextRoles.stream().filter(res -> {
            return org.apache.commons.lang3.StringUtils.equals(res.getRoleCode(), "00000000000000000000000000000000");
        }).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(filter)) {
            return;
        }
        YwuContextRole guestRole = new YwuContextRole();
        guestRole.setRoleCode("00000000000000000000000000000000");
        guestRole.setRoleName("游客");
        guestRole.setRoleDescription("游客");
        guestRole.setId(24);
        ywuContextRoles.add(guestRole);
    }
}
